package com.chentf.a02_applicationContext;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.annotation.Resource;

/**
 * @author chentengfei
 * @desc ...
 * @date 2023-03-22 16:39:00
 */
public class TestBeanFactory {

    public static void main(String[] args) {

        // 定义bean工厂
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        // bean 的定义（class, scope, 初始化, 销毁）
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(config.class)
                    .setScope("singleton").getBeanDefinition();
        //注册bean
        beanFactory.registerBeanDefinition("config", beanDefinition);

        // 给 BeanFactory 添加一些常用的后处理器
        AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);

        // BeanFactory 后处理器主要功能，补充了一些 bean 定义
        beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values()
                    .forEach(beanFactoryPostProcessor -> {
                        // 执行bean工厂后置处理器，解析@Configuration，@bean注解的bean
                        beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
                    });

        // Bean 后处理器, 针对 bean 的生命周期的各个阶段提供扩展, 例如 @Autowired @Resource ...
        beanFactory.getBeansOfType(BeanPostProcessor.class).values()
                    .stream()
                    .sorted(beanFactory.getDependencyComparator()) //排序功能，数字越大，优先级越低，排序越后，优先级按照升序排
                    .forEach(beanPostProcessor -> {
                        System.out.println(">>>"+beanPostProcessor);
                        beanFactory.addBeanPostProcessor(beanPostProcessor); //给bean工厂中添加后置处理bean
                    });

        //打印所有bean名称
        for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }

        beanFactory.preInstantiateSingletons(); //准备所有的单例对象
        System.out.println(">>>>>>>>>>>>>>>>>>>>>");
        System.out.println(beanFactory.getBean(Bean1.class).getBean2());
        System.out.println(beanFactory.getBean(Bean1.class).getInter());
        /*
            学到了什么:
            a. beanFactory 不会做的事
                   1. 不会主动调用 BeanFactory 后处理器
                   2. 不会主动添加 Bean 后处理器
                   3. 不会主动初始化单例
                   4. 不会解析beanFactory 还不会解析 ${ } 与 #{ }
            b. bean 后处理器会有排序的逻辑
         */

        //spring中注册bean的order排序规则
        System.out.println("Common:" + (Ordered.LOWEST_PRECEDENCE - 3));
        System.out.println("Autowired:" + (Ordered.LOWEST_PRECEDENCE - 2));


    }

    @Configuration
    static class config{

        @Bean
        public Bean1 bean1(){
            return new Bean1();
        }

        @Bean
        public Bean2 bean2(){
            return new Bean2();
        }

        @Bean
        public Bean3 bean3(){
            return new Bean3();
        }

        @Bean
        public Bean4 bean4(){
            return new Bean4();
        }
    }

    interface Inter{}

    static class Bean3 implements Inter{}

    static class Bean4 implements Inter{}

    static class Bean1{
        private static final Logger log = LoggerFactory.getLogger(Bean1.class);

        public Bean1(){
            log.debug("构造方法构造Bean1()");
        }

        @Autowired
        private Bean2 bean2; //注入Bean2

        public Bean2 getBean2(){
            return bean2;
        }

        @Autowired //注入bean3
        @Resource(name = "bean4") //resource注入bean4
        private Inter bean3;

        public Inter getInter(){
            return  bean3;
        }
    }

    static class Bean2{
        private static final Logger log = LoggerFactory.getLogger(Bean2.class);

        public Bean2(){
            log.debug("构造方法构造Bean2");
        }
    }

}
